﻿// The Basic Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234237

namespace PlayToReceiver
{
    using System;
    using System.Collections.Generic;
    using Windows.Media.PlayTo;
    using Windows.Storage.Streams;
    using Windows.System.Display;
    using Windows.UI.Core;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Media;
    using System.Threading.Tasks;
    using Windows.UI.Popups;
    using PlayToReceiver.Common;

    /// <summary>
    /// A basic page that provides characteristics common to most applications.
    /// </summary>
    public sealed partial class MainPage : LayoutAwarePage
    {
        #region Constructors and Fields

        private CoreDispatcher dispatcher;

        private DisplayRequest display;

        private PlayToReceiver receiver;

        private bool seeking;

        public MainPage()
        {
            this.InitializeComponent();
        }

        #endregion

        #region Methods

        private async void StartReceiverButton_Click(object sender, RoutedEventArgs e) { await StartPlayTo(); }

        private async Task<bool> StartPlayTo()
        {
            try
            {
                this.dispatcher = Window.Current.CoreWindow.Dispatcher;

                if (this.receiver == null)
                {
                    this.receiver = new PlayToReceiver();
                }

                // Add Play To Receiver events and properties
                this.receiver.CurrentTimeChangeRequested += this.receiver_CurrentTimeChangeRequested;
                this.receiver.MuteChangeRequested += this.receiver_MuteChangeRequested;
                this.receiver.PauseRequested += this.receiver_PauseRequested;
                this.receiver.PlaybackRateChangeRequested += this.receiver_PlaybackRateChangeRequested;
                this.receiver.PlayRequested += this.receiver_PlayRequested;
                this.receiver.SourceChangeRequested += this.receiver_SourceChangeRequested;
                this.receiver.StopRequested += this.receiver_StopRequested;
                this.receiver.TimeUpdateRequested += this.receiver_TimeUpdateRequested;
                this.receiver.VolumeChangeRequested += this.receiver_VolumeChangeRequested;

                this.receiver.FriendlyName = "Advanced XAML PlayTo";
                this.receiver.SupportsAudio = true;
                this.receiver.SupportsVideo = true;
                this.receiver.SupportsImage = true;

                // Add MediaElement events
                this.VideoPlayer.CurrentStateChanged += this.VideoPlayer_CurrentStateChanged;
                this.VideoPlayer.MediaEnded += this.VideoPlayer_MediaEnded;
                this.VideoPlayer.MediaFailed += this.VideoPlayer_MediaFailed;
                this.VideoPlayer.MediaOpened += this.VideoPlayer_MediaOpened;
                this.VideoPlayer.RateChanged += this.VideoPlayer_RateChanged;
                this.VideoPlayer.SeekCompleted += this.VideoPlayer_SeekCompleted;
                this.VideoPlayer.VolumeChanged += this.VideoPlayer_VolumeChanged;

                // Advertise the receiver on the local network and start receiving commands
                await this.receiver.StartAsync();

                // Prevent the screen from locking
                if (this.display == null)
                {
                    this.display = new DisplayRequest();
                }
                this.display.RequestActive();

                return true;
            }
            catch
            {
                this.receiver = null;
                return false;
            }
        }

        private async void StopReceiverButton_Click(object sender, RoutedEventArgs e) { await StopPlayTo(); }

        private async Task<bool> StopPlayTo()
        {
            try
            {
                if (this.receiver != null)
                {
                    await this.receiver.StopAsync();

                    if (this.display != null)
                    {
                        this.display.RequestRelease();
                    }

                    // Remove Play To Receiver events
                    this.receiver.CurrentTimeChangeRequested -= this.receiver_CurrentTimeChangeRequested;
                    this.receiver.MuteChangeRequested -= this.receiver_MuteChangeRequested;
                    this.receiver.PauseRequested -= this.receiver_PauseRequested;
                    this.receiver.PlaybackRateChangeRequested -= this.receiver_PlaybackRateChangeRequested;
                    this.receiver.PlayRequested -= this.receiver_PlayRequested;
                    this.receiver.SourceChangeRequested -= this.receiver_SourceChangeRequested;
                    this.receiver.StopRequested -= this.receiver_StopRequested;
                    this.receiver.TimeUpdateRequested -= this.receiver_TimeUpdateRequested;
                    this.receiver.VolumeChangeRequested -= this.receiver_VolumeChangeRequested;

                    //  Remove MediaElement events
                    this.VideoPlayer.Pause();

                    this.VideoPlayer.CurrentStateChanged -= this.VideoPlayer_CurrentStateChanged;
                    this.VideoPlayer.MediaEnded -= this.VideoPlayer_MediaEnded;
                    this.VideoPlayer.MediaFailed -= this.VideoPlayer_MediaFailed;
                    this.VideoPlayer.MediaOpened -= this.VideoPlayer_MediaOpened;
                    this.VideoPlayer.RateChanged -= this.VideoPlayer_RateChanged;
                    this.VideoPlayer.SeekCompleted -= this.VideoPlayer_SeekCompleted;
                    this.VideoPlayer.VolumeChanged -= this.VideoPlayer_VolumeChanged;

                    return true;
                }
            }
            catch
            {
                return false;
            }
            return false;
        }

        private void VideoPlayer_CurrentStateChanged(object sender, RoutedEventArgs e)
        {
            if (this.receiver != null)
            {
                switch (this.VideoPlayer.CurrentState)
                {
                    case MediaElementState.Playing:
                        this.receiver.NotifyPlaying();
                        break;
                    case MediaElementState.Paused:
                        this.receiver.NotifyPaused();
                        break;
                    case MediaElementState.Stopped:
                        this.receiver.NotifyStopped();
                        break;
                }
            }
        }

        private void VideoPlayer_MediaEnded(object sender, RoutedEventArgs e)
        {
            if (this.receiver != null)
            {
                this.receiver.NotifyEnded();
                this.VideoPlayer.Stop();
            }
        }

        private void VideoPlayer_MediaFailed(object sender, ExceptionRoutedEventArgs e)
        {
            if (this.receiver != null)
            {
                this.receiver.NotifyError();
            }
        }

        private void VideoPlayer_MediaOpened(object sender, RoutedEventArgs e)
        {
            if (this.receiver != null)
            {
                this.receiver.NotifyDurationChange(this.VideoPlayer.NaturalDuration.TimeSpan);
                this.receiver.NotifyLoadedMetadata();
            }
        }

        private void VideoPlayer_RateChanged(object sender, RateChangedRoutedEventArgs e)
        {
            if (this.receiver != null)
            {
                this.receiver.NotifyRateChange(this.VideoPlayer.PlaybackRate);
            }
        }

        private void VideoPlayer_SeekCompleted(object sender, RoutedEventArgs e)
        {
            if (this.receiver != null)
            {
                if (!this.seeking)
                {
                    this.receiver.NotifySeeking();
                }
                this.receiver.NotifySeeked();
                this.seeking = false;
            }
        }

        private void VideoPlayer_VolumeChanged(object sender, RoutedEventArgs e)
        {
            if (this.receiver != null)
            {
                this.receiver.NotifyVolumeChange(this.VideoPlayer.Volume, this.VideoPlayer.IsMuted);
            }
        }

        private async void receiver_CurrentTimeChangeRequested(
            PlayToReceiver sender, CurrentTimeChangeRequestedEventArgs args)
        {
            await this.dispatcher.RunAsync(
                CoreDispatcherPriority.Normal,
                () =>
                {
                    this.VideoPlayer.Position = args.Time;
                    this.receiver.NotifySeeking();
                    this.seeking = true;
                });
        }

        private async void receiver_MuteChangeRequested(PlayToReceiver sender, MuteChangeRequestedEventArgs args)
        {
            await
                this.dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { this.VideoPlayer.IsMuted = args.Mute; });
        }

        private async void receiver_PauseRequested(PlayToReceiver sender, object args)
        {
            await this.dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { this.VideoPlayer.Pause(); });
        }

        private async void receiver_PlayRequested(PlayToReceiver sender, object args)
        {
            await this.dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { this.VideoPlayer.Play(); });
        }

        private async void receiver_PlaybackRateChangeRequested(
            PlayToReceiver sender, PlaybackRateChangeRequestedEventArgs args)
        {
            await
                this.dispatcher.RunAsync(
                    CoreDispatcherPriority.Normal, () => { this.VideoPlayer.PlaybackRate = args.Rate; });
        }

        private async void receiver_SourceChangeRequested(PlayToReceiver sender, SourceChangeRequestedEventArgs args)
        {
            if (args.Stream != null)
            {
                await this.dispatcher.RunAsync(
                    CoreDispatcherPriority.Normal,
                    () =>
                    {
                        var stream = args.Stream as IRandomAccessStream;
                        this.VideoPlayer.SetSource(stream, args.Stream.ContentType);
                    });
            }
        }

        private async void receiver_StopRequested(PlayToReceiver sender, object args)
        {
            await this.dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { this.VideoPlayer.Stop(); });
        }

        private async void receiver_TimeUpdateRequested(PlayToReceiver sender, object args)
        {
            await this.dispatcher.RunAsync(
                CoreDispatcherPriority.Normal,
                () =>
                {
                    if (this.VideoPlayer.Position != null)
                    {
                        this.receiver.NotifyTimeUpdate(this.VideoPlayer.Position);
                    }
                });
        }

        private async void receiver_VolumeChangeRequested(PlayToReceiver sender, VolumeChangeRequestedEventArgs args)
        {
            await
                this.dispatcher.RunAsync(
                    CoreDispatcherPriority.Normal, () => { this.VideoPlayer.Volume = args.Volume; });
        }

        #endregion

        private async void ToggleSwitch_Toggled(object sender, RoutedEventArgs e)
        {
            var _Toggle = sender as ToggleSwitch;
            if (_Toggle.IsOn)
            {
                _Toggle.IsEnabled = false;
                if (!await StartPlayTo())
                {
                    new MessageDialog("Failed to start");
                    _Toggle.IsOn = false;
                }
                _Toggle.IsEnabled = true;
            }
            else
            {
                _Toggle.IsEnabled = false;
                if (!await StopPlayTo())
                {
                    new MessageDialog("Failed to stop");
                    _Toggle.IsOn = true;
                }
                _Toggle.IsEnabled = true;
            }
        }
    }
}